import base64
import json
import pickle

from django.http import JsonResponse
# base64 将 字典 ----> 通过pickle将Python数据序列化为 二进制 -----> 编码加密
# 解码： 编码解密 ---> 二进制 ---> pickle转为字典对象

from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU

"""
购物车功能:
    1. 登录用户购物车数据保存在哪里？？ --redis+mysql 频繁增删改查
    2. 未登录的用户购物车数据保存到哪里？ cookies
    保存的数据：
        redis:
            user_id, sku_id, count, selected
        cookie:
            sku_id, count, selected
    3. 数据组织：
        redis: 使用hash
            user_id, sku_id(商品id), count(数量, selected(选中状态）
            user_id: 
                    sku_id: count,
                    xxx_sku_id: selected
            优化：
                购物车商品信息 Hash
                    user_id: 
                        sku_id: count
                购物车选中状态
                    selected_id: Sets
                        {x, x, ,x, x}
            再优化：
                购物车商品信息 Hash  其中count的正负表示选中状态
                    user_id: 
                        sku_id: count
        cookie:
            {
            sku_id: {count: xxx, selected: xxx},
            sku_id: {count: xxx, selected: xxx},
            sku_id: {count: xxx, selected: xxx},
            }
"""


class CartView(View):
    """
    点击添加购物车时
    接受数据
    1. 用户是否登录， 没登录在cookies中添加数据-加密过的数据
    2. 用户已经登录， 查询redis中添加购物车数据
    3. 返回响应
    """

    def post(self, request):
        data = json.loads(request.body.decode())
        sku_id = data.get("sku_id")
        count = data.get('count')

        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '没有该商品'})
        try:
            count = int(count)
        except Exception as e:
            count = 1

        user = request.user
        # 判断用户登录状态
        if request.user.is_authenticated:
            # 连接数据库
            redis_cli = get_redis_connection('carts')
            pipe = redis_cli.pipeline()
            # 加入数据 数量信息
            pipe.hincrby('carts_%s' % user.id, sku_id, count)
            pipe.sadd('selected_%s' % user.id, sku_id)
            pipe.execute()
            return JsonResponse({'code': 0, 'errmsg': 'ok'})
        else:
            resp = JsonResponse({'code': 0, 'errmsg': 'ok'})
            # 获取cookies
            data = request.COOKIES.get("carts")
            if data:
                carts = pickle.loads(base64.b64decode(data))
            else:
                carts = {}

            if sku_id in carts:
                origin_count = carts[sku_id]['count']
                count += origin_count

            carts[sku_id] = {
                'count': count,
                'selected': True,
            }
            carts_bytes = pickle.dumps(carts)
            # base64encode是二进制类型, 加decode转为字符串数据
            base64encode = base64.b64encode(carts_bytes)
            resp.set_cookie('carts', base64encode.decode(), max_age=3600 * 24 * 12)
            return resp

    # 查询购物车数据，登录用户查redis，未登录用户查cookies
    """
        1. 判断登录
        2. 查数据
        3. 返回响应
    """

    def get(self, request):
        user = request.user
        # 登录用户
        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            sku_id_counts = redis_cli.hgetall('carts_%s' % user.id)
            selected_ids = redis_cli.smembers('selected_%s' % user.id)
            carts = {}
            for i in sku_id_counts:
                carts[int(i)] = {
                    'count': int(sku_id_counts[i]),
                    'selected': i in selected_ids,
                }
        else:
            # 获取cookies
            data = request.COOKIES.get("carts")
            if data:
                carts = pickle.loads(base64.b64decode(data))
            else:
                carts = {}

        # 根据商品id查询信息
        # 可以直接便利 carts
        # 也可以获取 字典最外层的key，最外层的所有key就是商品id
        sku_ids = carts.keys()
        # 查询所有的在购物车中的sku
        skus = SKU.objects.filter(id__in=sku_ids)

        sku_list = []
        for sku in skus:
            sku_list.append({
                'name': sku.name,
                'price': sku.price,
                'id': sku.id,
                'default_image_url': sku.default_image.url,
                'selected': carts[sku.id]['selected'],
                'count': int(carts[sku.id]['count']),
                'amount': sku.price * int(carts[sku.id]['count']),
            })
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'cart_skus': sku_list})

    """
        1. 获取用户信息
        接收数据， 验证数据
            登录的话：
                1. 连接redis
                2. 修改redis中的数据
                3. 返回响应
            未登录：
                1. 读取购物车的cookies
                2. 将cookies转为carts字典数据
                3. 更新字典数据
                4. 重新加密数据
                5. 重新设置cookies
                6. 返回响应
    """

    def put(self, request):
        user = request.user
        data = json.loads(request.body)
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected')
        if not all([sku_id, count]):
            return JsonResponse({'code': 400, 'errmsg': '参数不全'})
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '该商品数据不存在'})
        try:
            count = int(count)
        except Exception as e:
            count = 1

        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            # redis hash
            redis_cli.hset('cart_%s' % user.id, sku_id, count)
            # redis中的set结构
            if selected:
                redis_cli.sadd('selected_%s' % user.id, sku_id)
            else:
                redis_cli.srem('selected_%s' % user.id, sku_id)

        else:
            # 未登录用户更新cookies
            cookies_cart = request.COOKIES.get('carts')
            if cookies_cart:
                carts = pickle.loads(base64.b64decode(cookies_cart))
            else:
                carts = {}
            if sku_id in carts:
                carts[sku_id] = {
                    'count': count,
                    'selected': True if selected else False,
                }
            carts_byte = pickle.dumps(carts)
            encode_data = base64.b64encode(carts_byte)
            resp = JsonResponse({'code': 0, 'errmsg': 'ok'})
            resp.set_cookie('carts', encode_data.decode(), max_age=3600*24*12)
            return resp

    def delete(self, request):
        """
        接收器请求
        验证参数
        未登录用户操作cookies
        登录用户操作 redis
        """
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        user = request.user
        try:
            sku = SKU.objects.get(pk='sku_id')
        except SKU.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '没有商品数据'})

        if user.is_authenticated:
            redis_cli = get_redis_connection('carts')
            redis_cli.hdel('carts_%s' % user.id, sku_id)
            redis_cli.sadd('selected_%s' % user.id, sku_id)
        else:
            cookies_cart = request.COOKIES.get('cart')
            if cookies_cart:
                carts = pickle.loads(base64.b64decode(cookies_cart))
            else:
                carts = {}

        del carts[sku_id]
        new_carts = base64.b64encode(pickle.dumps(carts))
        resp = JsonResponse({'code': 0, 'errmsg': 'ok'})
        resp.set_cookie('carts', new_carts.decode(), max_age=12*3600*24)
        return resp
